package com.szcinda.service.dto.linePrice;

import com.szcinda.repository.*;
import com.szcinda.service.PageResult;
import com.szcinda.service.SnowFlakeFactory;
import com.szcinda.service.dto.log.LogCreateDto;
import com.szcinda.service.dto.log.LogService;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.time.Instant;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;

@Service
@Transactional
public class LinePriceServiceImpl implements LinePriceService {
    private final LinePriceRepository linePriceRepository;
    private final UserRepository userRepository;
    private final LogService logService;
    private final OrganizationRepository organizationRepository;
    private final SnowFlakeFactory snowFlakeFactory;

    public LinePriceServiceImpl(LinePriceRepository linePriceRepository, UserRepository userRepository, LogService logService, OrganizationRepository organizationRepository) {
        this.linePriceRepository = linePriceRepository;
        this.userRepository = userRepository;
        this.logService = logService;
        this.organizationRepository = organizationRepository;
        this.snowFlakeFactory = SnowFlakeFactory.getInstance();
    }

    @Override
    public void create(LinePriceCreateDto createDto) {
        LinePrice linePrice = new LinePrice();
        BeanUtils.copyProperties(createDto, linePrice);
        linePrice.setId(snowFlakeFactory.nextId("LP"));
        User user = userRepository.findById(linePrice.getOpId());
        Organization organization = organizationRepository.findById(createDto.getOrganizationId());
        linePrice.setOrganizationName(organization.getName());
        linePrice.setOpName(user.getNickName());
        linePriceRepository.save(linePrice);
        LogCreateDto logCreateDto = new LogCreateDto(user.getId(), user.getNickName(), "新增线路价格", "业务类型：" + linePrice.getBusinessType() + ",起始站：" + linePrice.getOriginPlace() + ",目的站：" + linePrice.getDestPlace());
        logService.create(logCreateDto);
    }

    @Override
    public void batchCreate(List<LinePriceImportDto> importDatas, String belongId, String opId, String organizationId, String feeType) {
        Organization organization = organizationRepository.findById(organizationId);
        List<LinePrice> linePrices = linePriceRepository.findByBelongId(belongId);
        for (LinePriceImportDto importData : importDatas) {
            // 检查是否存在，存在则更新，不存在则新增
            CalculateType type = CalculateTypeUtil.getCalculateType(importData.getCalculateType());
            LinePrice record = linePrices.stream().filter(linePrice -> linePrice.getBusinessType().equals(importData.getBusinessType()) && linePrice.getUnit().equals(importData.getUnit()) && linePrice.getOriginPlace().equals(importData.getOriginPlace()) && linePrice.getDestPlace().equals(importData.getDestPlace()) && linePrice.getDeparturePort().equals(importData.getDeparturePort()) && linePrice.getFeeName().equals(importData.getFeeName()) && linePrice.getCalculateType().equals(type)).findFirst().orElse(null);
            if (record != null) {
                record.setCurrency(importData.getCurrency());
                if (importData.getPrice() != null) {
                    record.setPrice(importData.getPrice());
                }
                if (importData.getCalculateType() != null) {
                    record.setCalculateType(CalculateTypeUtil.getCalculateType(importData.getCalculateType()));
                }
                if (importData.getStartDate() != null) {
                    Instant instant = importData.getStartDate().toInstant();
                    ZoneId zoneId = ZoneId.systemDefault();
                    // atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
                    record.setStartDate(instant.atZone(zoneId).toLocalDate());
                }
                if (importData.getEndDate() != null) {
                    Instant instant = importData.getEndDate().toInstant();
                    ZoneId zoneId = ZoneId.systemDefault();
                    // atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
                    record.setEndDate(instant.atZone(zoneId).toLocalDate());
                }
                if (importData.getPb() != null) {
                    record.setPb(Double.parseDouble(importData.getPb().replaceAll("1:", "").replaceAll("1：", "")));
                }
                // 按重量计费
                if (importData.getPrice() != null) {
                    record.setPrice(importData.getPrice());
                }
                // 按体积计费
                if (importData.getPrice2() != null) {
                    record.setPrice2(importData.getPrice2());
                }
                record.setRemark(importData.getRemark());
                linePriceRepository.save(record);
            } else {
                LinePriceCreateDto createDto = new LinePriceCreateDto();
                BeanUtils.copyProperties(importData, createDto);
                createDto.setBelongId(belongId);
                createDto.setOpId(opId);
                createDto.setFeeType(feeType);
                createDto.setOrganizationId(organization.getId());
                if (importData.getCalculateType() != null) {
                    createDto.setCalculateType(CalculateTypeUtil.getCalculateType(importData.getCalculateType()));
                }
                if (importData.getStartDate() != null) {
                    Instant instant = importData.getStartDate().toInstant();
                    ZoneId zoneId = ZoneId.systemDefault();
                    // atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
                    createDto.setStartDate(instant.atZone(zoneId).toLocalDate());
                }
                if (importData.getEndDate() != null) {
                    Instant instant = importData.getEndDate().toInstant();
                    ZoneId zoneId = ZoneId.systemDefault();
                    // atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
                    createDto.setEndDate(instant.atZone(zoneId).toLocalDate());
                }
                if (importData.getPb() != null) {
                    createDto.setPb(Double.parseDouble(importData.getPb().replaceAll("1:", "").replaceAll("1：", "")));
                }
                // 按重量计费
                if (importData.getPrice() != null) {
                    createDto.setPrice(importData.getPrice());
                }
                // 按体积计费
                if (importData.getPrice2() != null) {
                    createDto.setPrice2(importData.getPrice2());
                }
                create(createDto);
            }
        }
    }


    @Override
    public void update(LinePriceUpdateDto updateDto) {
        LinePrice linePrice = linePriceRepository.findById(updateDto.getId());
        BeanUtils.copyProperties(updateDto, linePrice, "id", "opId");
        User user = userRepository.findById(linePrice.getOpId());
        LogCreateDto logCreateDto = new LogCreateDto(user.getId(), user.getNickName(), "修改线路价格", "业务类型：" + linePrice.getBusinessType() + ",起始站：" + linePrice.getOriginPlace() + ",目的站：" + linePrice.getDestPlace());
        logService.create(logCreateDto);
    }

    @Override
    public PageResult<LinePrice> query(LinePriceQueryDto params) {
        Specification<LinePrice> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            Predicate belongId = criteriaBuilder.equal(root.get("belongId").as(String.class), params.getBelongId());
            predicates.add(belongId);
            if (!StringUtils.isEmpty(params.getBusinessType())) {
                Predicate businessType = criteriaBuilder.equal(root.get("businessType").as(String.class), params.getBusinessType());
                predicates.add(businessType);
            }
            if (!StringUtils.isEmpty(params.getTransportType())) {
                Predicate transportType = criteriaBuilder.equal(root.get("transportType").as(String.class), params.getTransportType());
                predicates.add(transportType);
            }
            if (!StringUtils.isEmpty(params.getUnit())) {
                Predicate unit = criteriaBuilder.equal(root.get("unit").as(String.class), params.getUnit());
                predicates.add(unit);
            }
            if (!StringUtils.isEmpty(params.getOriginPlace())) {
                Predicate originPlace = criteriaBuilder.like(root.get("originPlace").as(String.class), params.getOriginPlace().trim() + "%");
                predicates.add(originPlace);
            }
            if (!StringUtils.isEmpty(params.getDestPlace())) {
                Predicate destPlace = criteriaBuilder.like(root.get("destPlace").as(String.class), params.getDestPlace().trim() + "%");
                predicates.add(destPlace);
            }
            if (!StringUtils.isEmpty(params.getDeparturePort())) {
                Predicate departurePort = criteriaBuilder.equal(root.get("departurePort").as(String.class), params.getDeparturePort());
                predicates.add(departurePort);
            }
            if (!StringUtils.isEmpty(params.getFeeName())) {
                Predicate feeName = criteriaBuilder.equal(root.get("feeName").as(String.class), params.getFeeName());
                predicates.add(feeName);
            }
            if (!StringUtils.isEmpty(params.getFeeType())) {
                Predicate feeType = criteriaBuilder.equal(root.get("feeType").as(String.class), params.getFeeType());
                predicates.add(feeType);
            }
            if (!StringUtils.isEmpty(params.getCurrency())) {
                Predicate currency = criteriaBuilder.equal(root.get("currency").as(String.class), params.getCurrency());
                predicates.add(currency);
            }
            if (!StringUtils.isEmpty(params.getCalculateType())) {
                Predicate calculateType = criteriaBuilder.equal(root.get("calculateType").as(String.class), params.getCalculateType());
                predicates.add(calculateType);
            }
            if (params.getStartDate() != null) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("startDate"), params.getStartDate());
                predicates.add(timeStart);
            }
            if (params.getEndDate() != null) {
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("endDate"), params.getEndDate().plusDays(1));
                predicates.add(timeEnd);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        Pageable pageable = new PageRequest(params.getPage() - 1, params.getPageSize(), sort);
        Page<LinePrice> details = linePriceRepository.findAll(specification, pageable);
        return PageResult.of(details.getContent(), params.getPage(), params.getPageSize(), details.getTotalElements());
    }

    @Override
    public void delete(String id, String userId) {
        LinePrice linePrice = linePriceRepository.findById(id);
        linePriceRepository.delete(linePrice);
        User user = userRepository.findById(userId);
        LogCreateDto logCreateDto = new LogCreateDto(user.getId(), user.getNickName(), "删除线路价格", "业务类型：" + linePrice.getBusinessType() + ",起始站：" + linePrice.getOriginPlace() + ",目的站：" + linePrice.getDestPlace());
        logService.create(logCreateDto);
    }
}
